home *** CD-ROM | disk | FTP | other *** search
/ Download Now 8 / Download Now V8.iso / Program / InternetTools / ApacheWebServer1.3.6 / apache_1_3_6_win32.exe / _SETUP.1 / util.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-03-20  |  57.0 KB  |  2,186 lines

  1. /* ====================================================================
  2.  * Copyright (c) 1995-1999 The Apache Group.  All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  *
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer. 
  10.  *
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in
  13.  *    the documentation and/or other materials provided with the
  14.  *    distribution.
  15.  *
  16.  * 3. All advertising materials mentioning features or use of this
  17.  *    software must display the following acknowledgment:
  18.  *    "This product includes software developed by the Apache Group
  19.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  20.  *
  21.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  22.  *    endorse or promote products derived from this software without
  23.  *    prior written permission. For written permission, please contact
  24.  *    apache@apache.org.
  25.  *
  26.  * 5. Products derived from this software may not be called "Apache"
  27.  *    nor may "Apache" appear in their names without prior written
  28.  *    permission of the Apache Group.
  29.  *
  30.  * 6. Redistributions of any form whatsoever must retain the following
  31.  *    acknowledgment:
  32.  *    "This product includes software developed by the Apache Group
  33.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  36.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  37.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  38.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  41.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  42.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  43.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  44.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  45.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  46.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Group and was originally based
  51.  * on public domain software written at the National Center for
  52.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  53.  * For more information on the Apache Group and the Apache HTTP server
  54.  * project, please see <http://www.apache.org/>.
  55.  *
  56.  */
  57.  
  58. /*
  59.  * util.c: string utility things
  60.  * 
  61.  * 3/21/93 Rob McCool
  62.  * 1995-96 Many changes by the Apache Group
  63.  * 
  64.  */
  65.  
  66. /* Debugging aid:
  67.  * #define DEBUG            to trace all cfg_open*()/cfg_closefile() calls
  68.  * #define DEBUG_CFG_LINES  to trace every line read from the config files
  69.  */
  70.  
  71. #include "httpd.h"
  72. #include "http_conf_globals.h"    /* for user_id & group_id */
  73. #include "http_log.h"
  74. #if defined(SUNOS4)
  75. /* stdio.h has been read in ap_config.h already. Add missing prototypes here: */
  76. extern int fgetc(FILE *);
  77. extern char *fgets(char *s, int, FILE*);
  78. extern int fclose(FILE *);
  79. #endif
  80.  
  81. /* A bunch of functions in util.c scan strings looking for certain characters.
  82.  * To make that more efficient we encode a lookup table.  The test_char_table
  83.  * is generated automatically by gen_test_char.c.
  84.  */
  85. #include "test_char.h"
  86.  
  87. /* we assume the folks using this ensure 0 <= c < 256... which means
  88.  * you need a cast to (unsigned char) first, you can't just plug a
  89.  * char in here and get it to work, because if char is signed then it
  90.  * will first be sign extended.
  91.  */
  92. #define TEST_CHAR(c, f)    (test_char_table[(unsigned)(c)] & (f))
  93.  
  94. void ap_util_init(void)
  95. {
  96.     /* nothing to do... previously there was run-time initialization of
  97.      * test_char_table here
  98.      */
  99. }
  100.  
  101.  
  102. API_VAR_EXPORT const char ap_month_snames[12][4] =
  103. {
  104.     "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  105. };
  106. API_VAR_EXPORT const char ap_day_snames[7][4] =
  107. {
  108.     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  109. };
  110.  
  111. API_EXPORT(char *) ap_get_time()
  112. {
  113.     time_t t;
  114.     char *time_string;
  115.  
  116.     t = time(NULL);
  117.     time_string = ctime(&t);
  118.     time_string[strlen(time_string) - 1] = '\0';
  119.     return (time_string);
  120. }
  121.  
  122. API_EXPORT(char *) ap_ht_time(pool *p, time_t t, const char *fmt, int gmt)
  123. {
  124.     char ts[MAX_STRING_LEN];
  125.     char tf[MAX_STRING_LEN];
  126.     struct tm *tms;
  127.  
  128.     tms = (gmt ? gmtime(&t) : localtime(&t));
  129.     if(gmt) {
  130.     /* Convert %Z to "GMT" and %z to "+0000";
  131.      * on hosts that do not have a time zone string in struct tm,
  132.      * strftime must assume its argument is local time.
  133.      */
  134.     const char *f;
  135.     char *strp;
  136.     for(strp = tf, f = fmt; strp < tf + sizeof(tf) - 6 && (*strp = *f)
  137.         ; f++, strp++) {
  138.         if (*f != '%') continue;
  139.         switch (f[1]) {
  140.         case '%':
  141.         *++strp = *++f;
  142.         break;
  143.         case 'Z':
  144.         *strp++ = 'G';
  145.         *strp++ = 'M';
  146.         *strp = 'T';
  147.         f++;
  148.         break;
  149.         case 'z': /* common extension */
  150.         *strp++ = '+';
  151.         *strp++ = '0';
  152.         *strp++ = '0';
  153.         *strp++ = '0';
  154.         *strp = '0';
  155.         f++;
  156.         break;
  157.         }
  158.     }
  159.     *strp = '\0';
  160.     fmt = tf;
  161.     }
  162.  
  163.     /* check return code? */
  164.     strftime(ts, MAX_STRING_LEN, fmt, tms);
  165.     ts[MAX_STRING_LEN - 1] = '\0';
  166.     return ap_pstrdup(p, ts);
  167. }
  168.  
  169. API_EXPORT(char *) ap_gm_timestr_822(pool *p, time_t sec)
  170. {
  171.     struct tm *tms;
  172.  
  173.     tms = gmtime(&sec);
  174.  
  175.     /* RFC date format; as strftime '%a, %d %b %Y %T GMT' */
  176.     return ap_psprintf(p,
  177.         "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", ap_day_snames[tms->tm_wday],
  178.         tms->tm_mday, ap_month_snames[tms->tm_mon], tms->tm_year + 1900,
  179.         tms->tm_hour, tms->tm_min, tms->tm_sec);
  180. }
  181.  
  182. /* What a pain in the ass. */
  183. #if defined(HAVE_GMTOFF)
  184. API_EXPORT(struct tm *) ap_get_gmtoff(int *tz)
  185. {
  186.     time_t tt = time(NULL);
  187.     struct tm *t;
  188.  
  189.     t = localtime(&tt);
  190.     *tz = (int) (t->tm_gmtoff / 60);
  191.     return t;
  192. }
  193. #else
  194. API_EXPORT(struct tm *) ap_get_gmtoff(int *tz)
  195. {
  196.     time_t tt = time(NULL);
  197.     struct tm gmt;
  198.     struct tm *t;
  199.     int days, hours, minutes;
  200.  
  201.     /* Assume we are never more than 24 hours away. */
  202.     gmt = *gmtime(&tt);        /* remember gmtime/localtime return ptr to static */
  203.     t = localtime(&tt);        /* buffer... so be careful */
  204.     days = t->tm_yday - gmt.tm_yday;
  205.     hours = ((days < -1 ? 24 : 1 < days ? -24 : days * 24)
  206.          + t->tm_hour - gmt.tm_hour);
  207.     minutes = hours * 60 + t->tm_min - gmt.tm_min;
  208.     *tz = minutes;
  209.     return t;
  210. }
  211. #endif
  212.  
  213. /* Roy owes Rob beer. */
  214. /* Rob owes Roy dinner. */
  215.  
  216. /* These legacy comments would make a lot more sense if Roy hadn't
  217.  * replaced the old later_than() routine with util_date.c.
  218.  *
  219.  * Well, okay, they still wouldn't make any sense.
  220.  */
  221.  
  222. /* Match = 0, NoMatch = 1, Abort = -1
  223.  * Based loosely on sections of wildmat.c by Rich Salz
  224.  * Hmmm... shouldn't this really go component by component?
  225.  */
  226. API_EXPORT(int) ap_strcmp_match(const char *str, const char *exp)
  227. {
  228.     int x, y;
  229.  
  230.     for (x = 0, y = 0; exp[y]; ++y, ++x) {
  231.     if ((!str[x]) && (exp[y] != '*'))
  232.         return -1;
  233.     if (exp[y] == '*') {
  234.         while (exp[++y] == '*');
  235.         if (!exp[y])
  236.         return 0;
  237.         while (str[x]) {
  238.         int ret;
  239.         if ((ret = ap_strcmp_match(&str[x++], &exp[y])) != 1)
  240.             return ret;
  241.         }
  242.         return -1;
  243.     }
  244.     else if ((exp[y] != '?') && (str[x] != exp[y]))
  245.         return 1;
  246.     }
  247.     return (str[x] != '\0');
  248. }
  249.  
  250. API_EXPORT(int) ap_strcasecmp_match(const char *str, const char *exp)
  251. {
  252.     int x, y;
  253.  
  254.     for (x = 0, y = 0; exp[y]; ++y, ++x) {
  255.     if ((!str[x]) && (exp[y] != '*'))
  256.         return -1;
  257.     if (exp[y] == '*') {
  258.         while (exp[++y] == '*');
  259.         if (!exp[y])
  260.         return 0;
  261.         while (str[x]) {
  262.         int ret;
  263.         if ((ret = ap_strcasecmp_match(&str[x++], &exp[y])) != 1)
  264.             return ret;
  265.         }
  266.         return -1;
  267.     }
  268.     else if ((exp[y] != '?') && (ap_tolower(str[x]) != ap_tolower(exp[y])))
  269.         return 1;
  270.     }
  271.     return (str[x] != '\0');
  272. }
  273.  
  274. API_EXPORT(int) ap_is_matchexp(const char *str)
  275. {
  276.     register int x;
  277.  
  278.     for (x = 0; str[x]; x++)
  279.     if ((str[x] == '*') || (str[x] == '?'))
  280.         return 1;
  281.     return 0;
  282. }
  283.  
  284. /* This function substitutes for $0-$9, filling in regular expression
  285.  * submatches. Pass it the same nmatch and pmatch arguments that you
  286.  * passed regexec(). pmatch should not be greater than the maximum number
  287.  * of subexpressions - i.e. one more than the re_nsub member of regex_t.
  288.  *
  289.  * input should be the string with the $-expressions, source should be the
  290.  * string that was matched against.
  291.  *
  292.  * It returns the substituted string, or NULL on error.
  293.  *
  294.  * Parts of this code are based on Henry Spencer's regsub(), from his
  295.  * AT&T V8 regexp package.
  296.  */
  297.  
  298. API_EXPORT(char *) ap_pregsub(pool *p, const char *input, const char *source,
  299.                size_t nmatch, regmatch_t pmatch[])
  300. {
  301.     const char *src = input;
  302.     char *dest, *dst;
  303.     char c;
  304.     size_t no;
  305.     int len;
  306.  
  307.     if (!source)
  308.     return NULL;
  309.     if (!nmatch)
  310.     return ap_pstrdup(p, src);
  311.  
  312.     /* First pass, find the size */
  313.  
  314.     len = 0;
  315.  
  316.     while ((c = *src++) != '\0') {
  317.     if (c == '&')
  318.         no = 0;
  319.     else if (c == '$' && ap_isdigit(*src))
  320.         no = *src++ - '0';
  321.     else
  322.         no = 10;
  323.  
  324.     if (no > 9) {        /* Ordinary character. */
  325.         if (c == '\\' && (*src == '$' || *src == '&'))
  326.         c = *src++;
  327.         len++;
  328.     }
  329.     else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
  330.         len += pmatch[no].rm_eo - pmatch[no].rm_so;
  331.     }
  332.  
  333.     }
  334.  
  335.     dest = dst = ap_pcalloc(p, len + 1);
  336.  
  337.     /* Now actually fill in the string */
  338.  
  339.     src = input;
  340.  
  341.     while ((c = *src++) != '\0') {
  342.     if (c == '&')
  343.         no = 0;
  344.     else if (c == '$' && ap_isdigit(*src))
  345.         no = *src++ - '0';
  346.     else
  347.         no = 10;
  348.  
  349.     if (no > 9) {        /* Ordinary character. */
  350.         if (c == '\\' && (*src == '$' || *src == '&'))
  351.         c = *src++;
  352.         *dst++ = c;
  353.     }
  354.     else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
  355.         len = pmatch[no].rm_eo - pmatch[no].rm_so;
  356.         memcpy(dst, source + pmatch[no].rm_so, len);
  357.         dst += len;
  358.     }
  359.  
  360.     }
  361.     *dst = '\0';
  362.  
  363.     return dest;
  364. }
  365.  
  366. /*
  367.  * Parse .. so we don't compromise security
  368.  */
  369. API_EXPORT(void) ap_getparents(char *name)
  370. {
  371.     int l, w;
  372.  
  373.     /* Four paseses, as per RFC 1808 */
  374.     /* a) remove ./ path segments */
  375.  
  376.     for (l = 0, w = 0; name[l] != '\0';) {
  377.     if (name[l] == '.' && name[l + 1] == '/' && (l == 0 || name[l - 1] == '/'))
  378.         l += 2;
  379.     else
  380.         name[w++] = name[l++];
  381.     }
  382.  
  383.     /* b) remove trailing . path, segment */
  384.     if (w == 1 && name[0] == '.')
  385.     w--;
  386.     else if (w > 1 && name[w - 1] == '.' && name[w - 2] == '/')
  387.     w--;
  388.     name[w] = '\0';
  389.  
  390.     /* c) remove all xx/../ segments. (including leading ../ and /../) */
  391.     l = 0;
  392.  
  393.     while (name[l] != '\0') {
  394.     if (name[l] == '.' && name[l + 1] == '.' && name[l + 2] == '/' &&
  395.         (l == 0 || name[l - 1] == '/')) {
  396.         register int m = l + 3, n;
  397.  
  398.         l = l - 2;
  399.         if (l >= 0) {
  400.         while (l >= 0 && name[l] != '/')
  401.             l--;
  402.         l++;
  403.         }
  404.         else
  405.         l = 0;
  406.         n = l;
  407.         while ((name[n] = name[m]))
  408.         (++n, ++m);
  409.     }
  410.     else
  411.         ++l;
  412.     }
  413.  
  414.     /* d) remove trailing xx/.. segment. */
  415.     if (l == 2 && name[0] == '.' && name[1] == '.')
  416.     name[0] = '\0';
  417.     else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.' && name[l - 3] == '/') {
  418.     l = l - 4;
  419.     if (l >= 0) {
  420.         while (l >= 0 && name[l] != '/')
  421.         l--;
  422.         l++;
  423.     }
  424.     else
  425.         l = 0;
  426.     name[l] = '\0';
  427.     }
  428. }
  429.  
  430. API_EXPORT(void) ap_no2slash(char *name)
  431. {
  432.     char *d, *s;
  433.  
  434.     s = d = name;
  435.  
  436. #ifdef WIN32
  437.     /* Check for UNC names.  Leave leading two slashes. */
  438.     if (s[0] == '/' && s[1] == '/')
  439.         *d++ = *s++;
  440. #endif
  441.  
  442.     while (*s) {
  443.     if ((*d++ = *s) == '/') {
  444.         do {
  445.         ++s;
  446.         } while (*s == '/');
  447.     }
  448.     else {
  449.         ++s;
  450.     }
  451.     }
  452.     *d = '\0';
  453. }
  454.  
  455.  
  456. /*
  457.  * copy at most n leading directories of s into d
  458.  * d should be at least as large as s plus 1 extra byte
  459.  * assumes n > 0
  460.  * the return value is the ever useful pointer to the trailing \0 of d
  461.  *
  462.  * examples:
  463.  *    /a/b, 1  ==> /
  464.  *    /a/b, 2  ==> /a/
  465.  *    /a/b, 3  ==> /a/b/
  466.  *    /a/b, 4  ==> /a/b/
  467.  */
  468. API_EXPORT(char *) ap_make_dirstr_prefix(char *d, const char *s, int n)
  469. {
  470.     for (;;) {
  471.     *d = *s;
  472.     if (*d == '\0') {
  473.         *d = '/';
  474.         break;
  475.     }
  476.     if (*d == '/' && (--n) == 0)
  477.         break;
  478.     ++d;
  479.     ++s;
  480.     }
  481.     *++d = 0;
  482.     return (d);
  483. }
  484.  
  485.  
  486. /*
  487.  * return the parent directory name including trailing / of the file s
  488.  */
  489. API_EXPORT(char *) ap_make_dirstr_parent(pool *p, const char *s)
  490. {
  491.     char *last_slash = strrchr(s, '/');
  492.     char *d;
  493.     int l;
  494.  
  495.     if (last_slash == NULL) {
  496.     /* XXX: well this is really broken if this happens */
  497.     return (ap_pstrdup(p, "/"));
  498.     }
  499.     l = (last_slash - s) + 1;
  500.     d = ap_palloc(p, l + 1);
  501.     memcpy(d, s, l);
  502.     d[l] = 0;
  503.     return (d);
  504. }
  505.  
  506.  
  507. /*
  508.  * This function is deprecated.  Use one of the preceeding two functions
  509.  * which are faster.
  510.  */
  511. API_EXPORT(char *) ap_make_dirstr(pool *p, const char *s, int n)
  512. {
  513.     register int x, f;
  514.     char *res;
  515.  
  516.     for (x = 0, f = 0; s[x]; x++) {
  517.     if (s[x] == '/')
  518.         if ((++f) == n) {
  519.         res = ap_palloc(p, x + 2);
  520.         memcpy(res, s, x);
  521.         res[x] = '/';
  522.         res[x + 1] = '\0';
  523.         return res;
  524.         }
  525.     }
  526.  
  527.     if (s[strlen(s) - 1] == '/')
  528.     return ap_pstrdup(p, s);
  529.     else
  530.     return ap_pstrcat(p, s, "/", NULL);
  531. }
  532.  
  533. API_EXPORT(int) ap_count_dirs(const char *path)
  534. {
  535.     register int x, n;
  536.  
  537.     for (x = 0, n = 0; path[x]; x++)
  538.     if (path[x] == '/')
  539.         n++;
  540.     return n;
  541. }
  542.  
  543.  
  544. API_EXPORT(void) ap_chdir_file(const char *file)
  545. {
  546.     const char *x;
  547.     char buf[HUGE_STRING_LEN];
  548.  
  549.     x = strrchr(file, '/');
  550.     if (x == NULL) {
  551.     chdir(file);
  552.     }
  553.     else if (x - file < sizeof(buf) - 1) {
  554.     memcpy(buf, file, x - file);
  555.     buf[x - file] = '\0';
  556.     chdir(buf);
  557.     }
  558.     /* XXX: well, this is a silly function, no method of reporting an
  559.      * error... ah well. */
  560. }
  561.  
  562. API_EXPORT(char *) ap_getword_nc(pool *atrans, char **line, char stop)
  563. {
  564.     return ap_getword(atrans, (const char **) line, stop);
  565. }
  566.  
  567. API_EXPORT(char *) ap_getword(pool *atrans, const char **line, char stop)
  568. {
  569.     char *pos = strchr(*line, stop);
  570.     char *res;
  571.  
  572.     if (!pos) {
  573.     res = ap_pstrdup(atrans, *line);
  574.     *line += strlen(*line);
  575.     return res;
  576.     }
  577.  
  578.     res = ap_pstrndup(atrans, *line, pos - *line);
  579.  
  580.     while (*pos == stop) {
  581.     ++pos;
  582.     }
  583.  
  584.     *line = pos;
  585.  
  586.     return res;
  587. }
  588.  
  589. API_EXPORT(char *) ap_getword_white_nc(pool *atrans, char **line)
  590. {
  591.     return ap_getword_white(atrans, (const char **) line);
  592. }
  593.  
  594. API_EXPORT(char *) ap_getword_white(pool *atrans, const char **line)
  595. {
  596.     int pos = -1, x;
  597.     char *res;
  598.  
  599.     for (x = 0; (*line)[x]; x++) {
  600.     if (ap_isspace((*line)[x])) {
  601.         pos = x;
  602.         break;
  603.     }
  604.     }
  605.  
  606.     if (pos == -1) {
  607.     res = ap_pstrdup(atrans, *line);
  608.     *line += strlen(*line);
  609.     return res;
  610.     }
  611.  
  612.     res = ap_palloc(atrans, pos + 1);
  613.     ap_cpystrn(res, *line, pos + 1);
  614.  
  615.     while (ap_isspace((*line)[pos]))
  616.     ++pos;
  617.  
  618.     *line += pos;
  619.  
  620.     return res;
  621. }
  622.  
  623. API_EXPORT(char *) ap_getword_nulls_nc(pool *atrans, char **line, char stop)
  624. {
  625.     return ap_getword_nulls(atrans, (const char **) line, stop);
  626. }
  627.  
  628. API_EXPORT(char *) ap_getword_nulls(pool *atrans, const char **line, char stop)
  629. {
  630.     char *pos = strchr(*line, stop);
  631.     char *res;
  632.  
  633.     if (!pos) {
  634.     res = ap_pstrdup(atrans, *line);
  635.     *line += strlen(*line);
  636.     return res;
  637.     }
  638.  
  639.     res = ap_pstrndup(atrans, *line, pos - *line);
  640.  
  641.     ++pos;
  642.  
  643.     *line = pos;
  644.  
  645.     return res;
  646. }
  647.  
  648. /* Get a word, (new) config-file style --- quoted strings and backslashes
  649.  * all honored
  650.  */
  651.  
  652. static char *substring_conf(pool *p, const char *start, int len, char quote)
  653. {
  654.     char *result = ap_palloc(p, len + 2);
  655.     char *resp = result;
  656.     int i;
  657.  
  658.     for (i = 0; i < len; ++i) {
  659.     if (start[i] == '\\' && (start[i + 1] == '\\'
  660.                  || (quote && start[i + 1] == quote)))
  661.         *resp++ = start[++i];
  662.     else
  663.         *resp++ = start[i];
  664.     }
  665.  
  666.     *resp++ = '\0';
  667.     return result;
  668. }
  669.  
  670. API_EXPORT(char *) ap_getword_conf_nc(pool *p, char **line)
  671. {
  672.     return ap_getword_conf(p, (const char **) line);
  673. }
  674.  
  675. API_EXPORT(char *) ap_getword_conf(pool *p, const char **line)
  676. {
  677.     const char *str = *line, *strend;
  678.     char *res;
  679.     char quote;
  680.  
  681.     while (*str && ap_isspace(*str))
  682.     ++str;
  683.  
  684.     if (!*str) {
  685.     *line = str;
  686.     return "";
  687.     }
  688.  
  689.     if ((quote = *str) == '"' || quote == '\'') {
  690.     strend = str + 1;
  691.     while (*strend && *strend != quote) {
  692.         if (*strend == '\\' && strend[1] && strend[1] == quote)
  693.         strend += 2;
  694.         else
  695.         ++strend;
  696.     }
  697.     res = substring_conf(p, str + 1, strend - str - 1, quote);
  698.  
  699.     if (*strend == quote)
  700.         ++strend;
  701.     }
  702.     else {
  703.     strend = str;
  704.     while (*strend && !ap_isspace(*strend))
  705.         ++strend;
  706.  
  707.     res = substring_conf(p, str, strend - str, 0);
  708.     }
  709.  
  710.     while (*strend && ap_isspace(*strend))
  711.     ++strend;
  712.     *line = strend;
  713.     return res;
  714. }
  715.  
  716. API_EXPORT(int) ap_cfg_closefile(configfile_t *cfp)
  717. {
  718. #ifdef DEBUG
  719.     ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, NULL, 
  720.         "Done with config file %s", cfp->name);
  721. #endif
  722.     return (cfp->close == NULL) ? 0 : cfp->close(cfp->param);
  723. }
  724.  
  725. /* Common structure that holds the file and pool for ap_pcfg_openfile */
  726. typedef struct {
  727.     struct pool *pool;
  728.     FILE *file;
  729. } poolfile_t;
  730.  
  731. static int cfg_close(void *param)
  732. {
  733.     poolfile_t *cfp = (poolfile_t *) param;
  734.     return (ap_pfclose(cfp->pool, cfp->file));
  735. }
  736.  
  737. static int cfg_getch(void *param)
  738. {
  739.     poolfile_t *cfp = (poolfile_t *) param;
  740.     return (fgetc(cfp->file));
  741. }
  742.  
  743. static void *cfg_getstr(void *buf, size_t bufsiz, void *param)
  744. {
  745.     poolfile_t *cfp = (poolfile_t *) param;
  746.     return (fgets(buf, bufsiz, cfp->file));
  747. }
  748.  
  749. /* Open a configfile_t as FILE, return open configfile_t struct pointer */
  750. API_EXPORT(configfile_t *) ap_pcfg_openfile(pool *p, const char *name)
  751. {
  752.     configfile_t *new_cfg;
  753.     poolfile_t *new_pfile;
  754.     FILE *file;
  755.     struct stat stbuf;
  756.     int saved_errno;
  757.  
  758.     if (name == NULL) {
  759.         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, NULL,
  760.                "Internal error: pcfg_openfile() called with NULL filename");
  761.         return NULL;
  762.     }
  763.  
  764.     if (!ap_os_is_filename_valid(name)) {
  765.         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, NULL,
  766.                     "Access to config file %s denied: not a valid filename",
  767.                     name);
  768.     errno = EACCES;
  769.         return NULL;
  770.     }
  771.  
  772.     file = ap_pfopen(p, name, "r");
  773. #ifdef DEBUG
  774.     saved_errno = errno;
  775.     ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, NULL,
  776.                 "Opening config file %s (%s)",
  777.                 name, (file == NULL) ? strerror(errno) : "successful");
  778.     errno = saved_errno;
  779. #endif
  780.     if (file == NULL)
  781.         return NULL;
  782.  
  783.     if (fstat(fileno(file), &stbuf) == 0 &&
  784.         !S_ISREG(stbuf.st_mode) &&
  785. #if defined(WIN32) || defined(OS2)
  786.         !(strcasecmp(name, "nul") == 0 ||
  787.           (strlen(name) >= 4 &&
  788.            strcasecmp(name + strlen(name) - 4, "/nul") == 0))) {
  789. #else
  790.         strcmp(name, "/dev/null") != 0) {
  791. #endif /* WIN32 || OS2 */
  792.     saved_errno = errno;
  793.         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, NULL,
  794.                     "Access to file %s denied by server: not a regular file",
  795.                     name);
  796.         ap_pfclose(p, file);
  797.     errno = saved_errno;
  798.         return NULL;
  799.     }
  800.  
  801.     new_cfg = ap_palloc(p, sizeof(*new_cfg));
  802.     new_pfile = ap_palloc(p, sizeof(*new_pfile));
  803.     new_pfile->file = file;
  804.     new_pfile->pool = p;
  805.     new_cfg->param = new_pfile;
  806.     new_cfg->name = ap_pstrdup(p, name);
  807.     new_cfg->getch = (int (*)(void *)) cfg_getch;
  808.     new_cfg->getstr = (void *(*)(void *, size_t, void *)) cfg_getstr;
  809.     new_cfg->close = (int (*)(void *)) cfg_close;
  810.     new_cfg->line_number = 0;
  811.     return new_cfg;
  812. }
  813.  
  814.  
  815. /* Allocate a configfile_t handle with user defined functions and params */
  816. API_EXPORT(configfile_t *) ap_pcfg_open_custom(pool *p, const char *descr,
  817.     void *param,
  818.     int(*getch)(void *param),
  819.     void *(*getstr) (void *buf, size_t bufsiz, void *param),
  820.     int(*close_func)(void *param))
  821. {
  822.     configfile_t *new_cfg = ap_palloc(p, sizeof(*new_cfg));
  823. #ifdef DEBUG
  824.     ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, NULL, "Opening config handler %s", descr);
  825. #endif
  826.     new_cfg->param = param;
  827.     new_cfg->name = descr;
  828.     new_cfg->getch = getch;
  829.     new_cfg->getstr = getstr;
  830.     new_cfg->close = close_func;
  831.     new_cfg->line_number = 0;
  832.     return new_cfg;
  833. }
  834.  
  835.  
  836. /* Read one character from a configfile_t */
  837. API_EXPORT(int) ap_cfg_getc(configfile_t *cfp)
  838. {
  839.     register int ch = cfp->getch(cfp->param);
  840.     if (ch == LF) 
  841.     ++cfp->line_number;
  842.     return ch;
  843. }
  844.  
  845.  
  846. /* Read one line from open configfile_t, strip LF, increase line number */
  847. /* If custom handler does not define a getstr() function, read char by char */
  848. API_EXPORT(int) ap_cfg_getline(char *buf, size_t bufsize, configfile_t *cfp)
  849. {
  850.     /* If a "get string" function is defined, use it */
  851.     if (cfp->getstr != NULL) {
  852.     char *src, *dst;
  853.     char *cp;
  854.     char *cbuf = buf;
  855.     size_t cbufsize = bufsize;
  856.  
  857.     while (1) {
  858.         ++cfp->line_number;
  859.         if (cfp->getstr(cbuf, cbufsize, cfp->param) == NULL)
  860.         return 1;
  861.  
  862.         /*
  863.          *  check for line continuation,
  864.          *  i.e. match [^\\]\\[\r]\n only
  865.          */
  866.         cp = cbuf;
  867.         while (cp < cbuf+cbufsize && *cp != '\0')
  868.         cp++;
  869.         if (cp > cbuf && cp[-1] == LF) {
  870.         cp--;
  871.         if (cp > cbuf && cp[-1] == CR)
  872.             cp--;
  873.         if (cp > cbuf && cp[-1] == '\\') {
  874.             cp--;
  875.             if (!(cp > cbuf && cp[-1] == '\\')) {
  876.             /*
  877.              * line continuation requested -
  878.              * then remove backslash and continue
  879.              */
  880.             cbufsize -= (cp-cbuf);
  881.             cbuf = cp;
  882.             continue;
  883.             }
  884.             else {
  885.             /* 
  886.              * no real continuation because escaped -
  887.              * then just remove escape character
  888.              */
  889.             for ( ; cp < cbuf+cbufsize && *cp != '\0'; cp++)
  890.                 cp[0] = cp[1];
  891.             }   
  892.         }
  893.         }
  894.         break;
  895.     }
  896.  
  897.     /*
  898.      * Leading and trailing white space is eliminated completely
  899.      */
  900.     src = buf;
  901.     while (ap_isspace(*src))
  902.         ++src;
  903.     /* blast trailing whitespace */
  904.     dst = &src[strlen(src)];
  905.     while (--dst >= src && ap_isspace(*dst))
  906.         *dst = '\0';
  907.         /* Zap leading whitespace by shifting */
  908.         if (src != buf)
  909.         for (dst = buf; (*dst++ = *src++) != '\0'; )
  910.             ;
  911.  
  912. #ifdef DEBUG_CFG_LINES
  913.     ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, NULL, "Read config: %s", buf);
  914. #endif
  915.     return 0;
  916.     } else {
  917.     /* No "get string" function defined; read character by character */
  918.     register int c;
  919.     register size_t i = 0;
  920.  
  921.     buf[0] = '\0';
  922.     /* skip leading whitespace */
  923.     do {
  924.         c = cfp->getch(cfp->param);
  925.     } while (c == '\t' || c == ' ');
  926.  
  927.     if (c == EOF)
  928.         return 1;
  929.     
  930.     if(bufsize < 2) {
  931.         /* too small, assume caller is crazy */
  932.         return 1;
  933.     }
  934.  
  935.     while (1) {
  936.         if ((c == '\t') || (c == ' ')) {
  937.         buf[i++] = ' ';
  938.         while ((c == '\t') || (c == ' '))
  939.             c = cfp->getch(cfp->param);
  940.         }
  941.         if (c == CR) {
  942.         /* silently ignore CR (_assume_ that a LF follows) */
  943.         c = cfp->getch(cfp->param);
  944.         }
  945.         if (c == LF) {
  946.         /* increase line number and return on LF */
  947.         ++cfp->line_number;
  948.         }
  949.         if (c == EOF || c == 0x4 || c == LF || i >= (bufsize - 2)) {
  950.         /* 
  951.          *  check for line continuation
  952.          */
  953.         if (i > 0 && buf[i-1] == '\\') {
  954.             i--;
  955.             if (!(i > 0 && buf[i-1] == '\\')) {
  956.             /* line is continued */
  957.             c = cfp->getch(cfp->param);
  958.             continue;
  959.             }
  960.             /* else nothing needs be done because
  961.              * then the backslash is escaped and
  962.              * we just strip to a single one
  963.              */
  964.         }
  965.         /* blast trailing whitespace */
  966.         while (i > 0 && ap_isspace(buf[i - 1]))
  967.             --i;
  968.         buf[i] = '\0';
  969. #ifdef DEBUG_CFG_LINES
  970.         ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, NULL, "Read config: %s", buf);
  971. #endif
  972.         return 0;
  973.         }
  974.         buf[i] = c;
  975.         ++i;
  976.         c = cfp->getch(cfp->param);
  977.     }
  978.     }
  979. }
  980.  
  981. /* Size an HTTP header field list item, as separated by a comma.
  982.  * The return value is a pointer to the beginning of the non-empty list item
  983.  * within the original string (or NULL if there is none) and the address
  984.  * of field is shifted to the next non-comma, non-whitespace character.
  985.  * len is the length of the item excluding any beginning whitespace.
  986.  */
  987. API_EXPORT(const char *) ap_size_list_item(const char **field, int *len)
  988. {
  989.     const unsigned char *ptr = (const unsigned char *)*field;
  990.     const unsigned char *token;
  991.     int in_qpair, in_qstr, in_com;
  992.  
  993.     /* Find first non-comma, non-whitespace byte */
  994.  
  995.     while (*ptr == ',' || ap_isspace(*ptr))
  996.         ++ptr;
  997.  
  998.     token = ptr;
  999.  
  1000.     /* Find the end of this item, skipping over dead bits */
  1001.  
  1002.     for (in_qpair = in_qstr = in_com = 0;
  1003.          *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
  1004.          ++ptr) {
  1005.  
  1006.         if (in_qpair) {
  1007.             in_qpair = 0;
  1008.         }
  1009.         else {
  1010.             switch (*ptr) {
  1011.                 case '\\': in_qpair = 1;      /* quoted-pair         */
  1012.                            break;
  1013.                 case '"' : if (!in_com)       /* quoted string delim */
  1014.                                in_qstr = !in_qstr;
  1015.                            break;
  1016.                 case '(' : if (!in_qstr)      /* comment (may nest)  */
  1017.                                ++in_com;
  1018.                            break;
  1019.                 case ')' : if (in_com)        /* end comment         */
  1020.                                --in_com;
  1021.                            break;
  1022.                 default  : break;
  1023.             }
  1024.         }
  1025.     }
  1026.  
  1027.     if ((*len = (ptr - token)) == 0) {
  1028.         *field = ptr;
  1029.         return NULL;
  1030.     }
  1031.  
  1032.     /* Advance field pointer to the next non-comma, non-white byte */
  1033.  
  1034.     while (*ptr == ',' || ap_isspace(*ptr))
  1035.     ++ptr;
  1036.  
  1037.     *field = ptr;
  1038.     return (const char *)token;
  1039. }
  1040.  
  1041. /* Retrieve an HTTP header field list item, as separated by a comma,
  1042.  * while stripping insignificant whitespace and lowercasing anything not in
  1043.  * a quoted string or comment.  The return value is a new string containing
  1044.  * the converted list item (or NULL if none) and the address pointed to by
  1045.  * field is shifted to the next non-comma, non-whitespace.
  1046.  */
  1047. API_EXPORT(char *) ap_get_list_item(pool *p, const char **field)
  1048. {
  1049.     const char *tok_start;
  1050.     const unsigned char *ptr;
  1051.     unsigned char *pos;
  1052.     char *token;
  1053.     int addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0, tok_len = 0;
  1054.  
  1055.     /* Find the beginning and maximum length of the list item so that
  1056.      * we can allocate a buffer for the new string and reset the field.
  1057.      */
  1058.     if ((tok_start = ap_size_list_item(field, &tok_len)) == NULL) {
  1059.         return NULL;
  1060.     }
  1061.     token = ap_palloc(p, tok_len + 1);
  1062.  
  1063.     /* Scan the token again, but this time copy only the good bytes.
  1064.      * We skip extra whitespace and any whitespace around a '=', '/',
  1065.      * or ';' and lowercase normal characters not within a comment,
  1066.      * quoted-string or quoted-pair.
  1067.      */
  1068.     for (ptr = (const unsigned char *)tok_start, pos = (unsigned char *)token;
  1069.          *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
  1070.          ++ptr) {
  1071.  
  1072.         if (in_qpair) {
  1073.             in_qpair = 0;
  1074.             *pos++ = *ptr;
  1075.         }
  1076.         else {
  1077.             switch (*ptr) {
  1078.                 case '\\': in_qpair = 1;
  1079.                            if (addspace == 1)
  1080.                                *pos++ = ' ';
  1081.                            *pos++ = *ptr;
  1082.                            addspace = 0;
  1083.                            break;
  1084.                 case '"' : if (!in_com)
  1085.                                in_qstr = !in_qstr;
  1086.                            if (addspace == 1)
  1087.                                *pos++ = ' ';
  1088.                            *pos++ = *ptr;
  1089.                            addspace = 0;
  1090.                            break;
  1091.                 case '(' : if (!in_qstr)
  1092.                                ++in_com;
  1093.                            if (addspace == 1)
  1094.                                *pos++ = ' ';
  1095.                            *pos++ = *ptr;
  1096.                            addspace = 0;
  1097.                            break;
  1098.                 case ')' : if (in_com)
  1099.                                --in_com;
  1100.                            *pos++ = *ptr;
  1101.                            addspace = 0;
  1102.                            break;
  1103.                 case ' ' :
  1104.                 case '\t': if (addspace)
  1105.                                break;
  1106.                            if (in_com || in_qstr)
  1107.                                *pos++ = *ptr;
  1108.                            else
  1109.                                addspace = 1;
  1110.                            break;
  1111.                 case '=' :
  1112.                 case '/' :
  1113.                 case ';' : if (!(in_com || in_qstr))
  1114.                                addspace = -1;
  1115.                            *pos++ = *ptr;
  1116.                            break;
  1117.                 default  : if (addspace == 1)
  1118.                                *pos++ = ' ';
  1119.                            *pos++ = (in_com || in_qstr) ? *ptr
  1120.                                                         : ap_tolower(*ptr);
  1121.                            addspace = 0;
  1122.                            break;
  1123.             }
  1124.         }
  1125.     }
  1126.     *pos = '\0';
  1127.  
  1128.     return token;
  1129. }
  1130.  
  1131. /* Find an item in canonical form (lowercase, no extra spaces) within
  1132.  * an HTTP field value list.  Returns 1 if found, 0 if not found.
  1133.  * This would be much more efficient if we stored header fields as
  1134.  * an array of list items as they are received instead of a plain string.
  1135.  */
  1136. API_EXPORT(int) ap_find_list_item(pool *p, const char *line, const char *tok)
  1137. {
  1138.     const unsigned char *pos;
  1139.     const unsigned char *ptr = (const unsigned char *)line;
  1140.     int good = 0, addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0;
  1141.  
  1142.     if (!line || !tok)
  1143.         return 0;
  1144.  
  1145.     do {  /* loop for each item in line's list */
  1146.  
  1147.         /* Find first non-comma, non-whitespace byte */
  1148.  
  1149.         while (*ptr == ',' || ap_isspace(*ptr))
  1150.             ++ptr;
  1151.  
  1152.         if (*ptr)
  1153.             good = 1;  /* until proven otherwise for this item */
  1154.         else
  1155.             break;     /* no items left and nothing good found */
  1156.  
  1157.         /* We skip extra whitespace and any whitespace around a '=', '/',
  1158.          * or ';' and lowercase normal characters not within a comment,
  1159.          * quoted-string or quoted-pair.
  1160.          */
  1161.         for (pos = (const unsigned char *)tok;
  1162.              *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
  1163.              ++ptr) {
  1164.  
  1165.             if (in_qpair) {
  1166.                 in_qpair = 0;
  1167.                 if (good)
  1168.                     good = (*pos++ == *ptr);
  1169.             }
  1170.             else {
  1171.                 switch (*ptr) {
  1172.                     case '\\': in_qpair = 1;
  1173.                                if (addspace == 1)
  1174.                                    good = good && (*pos++ == ' ');
  1175.                                good = good && (*pos++ == *ptr);
  1176.                                addspace = 0;
  1177.                                break;
  1178.                     case '"' : if (!in_com)
  1179.                                    in_qstr = !in_qstr;
  1180.                                if (addspace == 1)
  1181.                                    good = good && (*pos++ == ' ');
  1182.                                good = good && (*pos++ == *ptr);
  1183.                                addspace = 0;
  1184.                                break;
  1185.                     case '(' : if (!in_qstr)
  1186.                                    ++in_com;
  1187.                                if (addspace == 1)
  1188.                                    good = good && (*pos++ == ' ');
  1189.                                good = good && (*pos++ == *ptr);
  1190.                                addspace = 0;
  1191.                                break;
  1192.                     case ')' : if (in_com)
  1193.                                    --in_com;
  1194.                                good = good && (*pos++ == *ptr);
  1195.                                addspace = 0;
  1196.                                break;
  1197.                     case ' ' :
  1198.                     case '\t': if (addspace || !good)
  1199.                                    break;
  1200.                                if (in_com || in_qstr)
  1201.                                    good = (*pos++ == *ptr);
  1202.                                else
  1203.                                    addspace = 1;
  1204.                                break;
  1205.                     case '=' :
  1206.                     case '/' :
  1207.                     case ';' : if (!(in_com || in_qstr))
  1208.                                    addspace = -1;
  1209.                                good = good && (*pos++ == *ptr);
  1210.                                break;
  1211.                     default  : if (!good)
  1212.                                    break;
  1213.                                if (addspace == 1)
  1214.                                    good = (*pos++ == ' ');
  1215.                                if (in_com || in_qstr)
  1216.                                    good = good && (*pos++ == *ptr);
  1217.                                else
  1218.                                    good = good && (*pos++ == ap_tolower(*ptr));
  1219.                                addspace = 0;
  1220.                                break;
  1221.                 }
  1222.             }
  1223.         }
  1224.         if (good && *pos)
  1225.             good = 0;          /* not good if only a prefix was matched */
  1226.  
  1227.     } while (*ptr && !good);
  1228.  
  1229.     return good;
  1230. }
  1231.  
  1232.  
  1233. /* Retrieve a token, spacing over it and returning a pointer to
  1234.  * the first non-white byte afterwards.  Note that these tokens
  1235.  * are delimited by semis and commas; and can also be delimited
  1236.  * by whitespace at the caller's option.
  1237.  */
  1238.  
  1239. API_EXPORT(char *) ap_get_token(pool *p, const char **accept_line, int accept_white)
  1240. {
  1241.     const char *ptr = *accept_line;
  1242.     const char *tok_start;
  1243.     char *token;
  1244.     int tok_len;
  1245.  
  1246.     /* Find first non-white byte */
  1247.  
  1248.     while (*ptr && ap_isspace(*ptr))
  1249.     ++ptr;
  1250.  
  1251.     tok_start = ptr;
  1252.  
  1253.     /* find token end, skipping over quoted strings.
  1254.      * (comments are already gone).
  1255.      */
  1256.  
  1257.     while (*ptr && (accept_white || !ap_isspace(*ptr))
  1258.        && *ptr != ';' && *ptr != ',') {
  1259.     if (*ptr++ == '"')
  1260.         while (*ptr)
  1261.         if (*ptr++ == '"')
  1262.             break;
  1263.     }
  1264.  
  1265.     tok_len = ptr - tok_start;
  1266.     token = ap_pstrndup(p, tok_start, tok_len);
  1267.  
  1268.     /* Advance accept_line pointer to the next non-white byte */
  1269.  
  1270.     while (*ptr && ap_isspace(*ptr))
  1271.     ++ptr;
  1272.  
  1273.     *accept_line = ptr;
  1274.     return token;
  1275. }
  1276.  
  1277.  
  1278. /* find http tokens, see the definition of token from RFC2068 */
  1279. API_EXPORT(int) ap_find_token(pool *p, const char *line, const char *tok)
  1280. {
  1281.     const unsigned char *start_token;
  1282.     const unsigned char *s;
  1283.  
  1284.     if (!line)
  1285.     return 0;
  1286.  
  1287.     s = (const unsigned char *)line;
  1288.     for (;;) {
  1289.     /* find start of token, skip all stop characters, note NUL
  1290.      * isn't a token stop, so we don't need to test for it
  1291.      */
  1292.     while (TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
  1293.         ++s;
  1294.     }
  1295.     if (!*s) {
  1296.         return 0;
  1297.     }
  1298.     start_token = s;
  1299.     /* find end of the token */
  1300.     while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
  1301.         ++s;
  1302.     }
  1303.     if (!strncasecmp((const char *)start_token, (const char *)tok, s - start_token)) {
  1304.         return 1;
  1305.     }
  1306.     if (!*s) {
  1307.         return 0;
  1308.     }
  1309.     }
  1310. }
  1311.  
  1312.  
  1313. API_EXPORT(int) ap_find_last_token(pool *p, const char *line, const char *tok)
  1314. {
  1315.     int llen, tlen, lidx;
  1316.  
  1317.     if (!line)
  1318.     return 0;
  1319.  
  1320.     llen = strlen(line);
  1321.     tlen = strlen(tok);
  1322.     lidx = llen - tlen;
  1323.  
  1324.     if ((lidx < 0) ||
  1325.     ((lidx > 0) && !(ap_isspace(line[lidx - 1]) || line[lidx - 1] == ',')))
  1326.     return 0;
  1327.  
  1328.     return (strncasecmp(&line[lidx], tok, tlen) == 0);
  1329. }
  1330.  
  1331. API_EXPORT(char *) ap_escape_shell_cmd(pool *p, const char *str)
  1332. {
  1333.     char *cmd;
  1334.     unsigned char *d;
  1335.     const unsigned char *s;
  1336.  
  1337.     cmd = ap_palloc(p, 2 * strlen(str) + 1);    /* Be safe */
  1338.     d = (unsigned char *)cmd;
  1339.     s = (const unsigned char *)str;
  1340.     for (; *s; ++s) {
  1341.  
  1342. #if defined(OS2) || defined(WIN32)
  1343.     /* Don't allow '&' in parameters under OS/2. */
  1344.     /* This can be used to send commands to the shell. */
  1345.     if (*s == '&') {
  1346.         *d++ = ' ';
  1347.         continue;
  1348.     }
  1349. #endif
  1350.  
  1351.     if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
  1352.         *d++ = '\\';
  1353.     }
  1354.     *d++ = *s;
  1355.     }
  1356.     *d = '\0';
  1357.  
  1358.     return cmd;
  1359. }
  1360.  
  1361. static char x2c(const char *what)
  1362. {
  1363.     register char digit;
  1364.  
  1365. #ifndef CHARSET_EBCDIC
  1366.     digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
  1367.     digit *= 16;
  1368.     digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
  1369. #else /*CHARSET_EBCDIC*/
  1370.     char xstr[5];
  1371.     xstr[0]='0';
  1372.     xstr[1]='x';
  1373.     xstr[2]=what[0];
  1374.     xstr[3]=what[1];
  1375.     xstr[4]='\0';
  1376.     digit = os_toebcdic[0xFF & strtol(xstr, NULL, 16)];
  1377. #endif /*CHARSET_EBCDIC*/
  1378.     return (digit);
  1379. }
  1380.  
  1381. /*
  1382.  * Unescapes a URL.
  1383.  * Returns 0 on success, non-zero on error
  1384.  * Failure is due to
  1385.  *   bad % escape       returns BAD_REQUEST
  1386.  *
  1387.  *   decoding %00 -> \0
  1388.  *   decoding %2f -> /   (a special character)
  1389.  *                      returns NOT_FOUND
  1390.  */
  1391. API_EXPORT(int) ap_unescape_url(char *url)
  1392. {
  1393.     register int x, y, badesc, badpath;
  1394.  
  1395.     badesc = 0;
  1396.     badpath = 0;
  1397.     for (x = 0, y = 0; url[y]; ++x, ++y) {
  1398.     if (url[y] != '%')
  1399.         url[x] = url[y];
  1400.     else {
  1401.         if (!ap_isxdigit(url[y + 1]) || !ap_isxdigit(url[y + 2])) {
  1402.         badesc = 1;
  1403.         url[x] = '%';
  1404.         }
  1405.         else {
  1406.         url[x] = x2c(&url[y + 1]);
  1407.         y += 2;
  1408.         if (url[x] == '/' || url[x] == '\0')
  1409.             badpath = 1;
  1410.         }
  1411.     }
  1412.     }
  1413.     url[x] = '\0';
  1414.     if (badesc)
  1415.     return BAD_REQUEST;
  1416.     else if (badpath)
  1417.     return NOT_FOUND;
  1418.     else
  1419.     return OK;
  1420. }
  1421.  
  1422. API_EXPORT(char *) ap_construct_server(pool *p, const char *hostname,
  1423.                     unsigned port, const request_rec *r)
  1424. {
  1425.     if (ap_is_default_port(port, r))
  1426.     return ap_pstrdup(p, hostname);
  1427.     else {
  1428.     return ap_psprintf(p, "%s:%u", hostname, port);
  1429.     }
  1430. }
  1431.  
  1432. /* c2x takes an unsigned, and expects the caller has guaranteed that
  1433.  * 0 <= what < 256... which usually means that you have to cast to
  1434.  * unsigned char first, because (unsigned)(char)(x) fist goes through
  1435.  * signed extension to an int before the unsigned cast.
  1436.  *
  1437.  * The reason for this assumption is to assist gcc code generation --
  1438.  * the unsigned char -> unsigned extension is already done earlier in
  1439.  * both uses of this code, so there's no need to waste time doing it
  1440.  * again.
  1441.  */
  1442. static const char c2x_table[] = "0123456789abcdef";
  1443.  
  1444. static ap_inline unsigned char *c2x(unsigned what, unsigned char *where)
  1445. {
  1446.     *where++ = '%';
  1447.     *where++ = c2x_table[what >> 4];
  1448.     *where++ = c2x_table[what & 0xf];
  1449.     return where;
  1450. }
  1451.  
  1452. /*
  1453.  * escape_path_segment() escapes a path segment, as defined in RFC 1808. This
  1454.  * routine is (should be) OS independent.
  1455.  *
  1456.  * os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
  1457.  * cases if a ':' occurs before the first '/' in the URL, the URL should be
  1458.  * prefixed with "./" (or the ':' escaped). In the case of Unix, this means
  1459.  * leaving '/' alone, but otherwise doing what escape_path_segment() does. For
  1460.  * efficiency reasons, we don't use escape_path_segment(), which is provided for
  1461.  * reference. Again, RFC 1808 is where this stuff is defined.
  1462.  *
  1463.  * If partial is set, os_escape_path() assumes that the path will be appended to
  1464.  * something with a '/' in it (and thus does not prefix "./").
  1465.  */
  1466.  
  1467. API_EXPORT(char *) ap_escape_path_segment(pool *p, const char *segment)
  1468. {
  1469.     char *copy = ap_palloc(p, 3 * strlen(segment) + 1);
  1470.     const unsigned char *s = (const unsigned char *)segment;
  1471.     unsigned char *d = (unsigned char *)copy;
  1472.     unsigned c;
  1473.  
  1474.     while ((c = *s)) {
  1475.     if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
  1476.         d = c2x(c, d);
  1477.     }
  1478.     else {
  1479.         *d++ = c;
  1480.     }
  1481.     ++s;
  1482.     }
  1483.     *d = '\0';
  1484.     return copy;
  1485. }
  1486.  
  1487. API_EXPORT(char *) ap_os_escape_path(pool *p, const char *path, int partial)
  1488. {
  1489.     char *copy = ap_palloc(p, 3 * strlen(path) + 3);
  1490.     const unsigned char *s = (const unsigned char *)path;
  1491.     unsigned char *d = (unsigned char *)copy;
  1492.     unsigned c;
  1493.  
  1494.     if (!partial) {
  1495.     char *colon = strchr(path, ':');
  1496.     char *slash = strchr(path, '/');
  1497.  
  1498.     if (colon && (!slash || colon < slash)) {
  1499.         *d++ = '.';
  1500.         *d++ = '/';
  1501.     }
  1502.     }
  1503.     while ((c = *s)) {
  1504.     if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
  1505.         d = c2x(c, d);
  1506.     }
  1507.     else {
  1508.         *d++ = c;
  1509.     }
  1510.     ++s;
  1511.     }
  1512.     *d = '\0';
  1513.     return copy;
  1514. }
  1515.  
  1516. /* ap_escape_uri is now a macro for os_escape_path */
  1517.  
  1518. API_EXPORT(char *) ap_escape_html(pool *p, const char *s)
  1519. {
  1520.     int i, j;
  1521.     char *x;
  1522.  
  1523.     /* first, count the number of extra characters */
  1524.     for (i = 0, j = 0; s[i] != '\0'; i++)
  1525.     if (s[i] == '<' || s[i] == '>')
  1526.         j += 3;
  1527.     else if (s[i] == '&')
  1528.         j += 4;
  1529.  
  1530.     if (j == 0)
  1531.     return ap_pstrndup(p, s, i);
  1532.  
  1533.     x = ap_palloc(p, i + j + 1);
  1534.     for (i = 0, j = 0; s[i] != '\0'; i++, j++)
  1535.     if (s[i] == '<') {
  1536.         memcpy(&x[j], "<", 4);
  1537.         j += 3;
  1538.     }
  1539.     else if (s[i] == '>') {
  1540.         memcpy(&x[j], ">", 4);
  1541.         j += 3;
  1542.     }
  1543.     else if (s[i] == '&') {
  1544.         memcpy(&x[j], "&", 5);
  1545.         j += 4;
  1546.     }
  1547.     else
  1548.         x[j] = s[i];
  1549.  
  1550.     x[j] = '\0';
  1551.     return x;
  1552. }
  1553.  
  1554. API_EXPORT(int) ap_is_directory(const char *path)
  1555. {
  1556.     struct stat finfo;
  1557.  
  1558.     if (stat(path, &finfo) == -1)
  1559.     return 0;        /* in error condition, just return no */
  1560.  
  1561.     return (S_ISDIR(finfo.st_mode));
  1562. }
  1563.  
  1564. API_EXPORT(char *) ap_make_full_path(pool *a, const char *src1,
  1565.                   const char *src2)
  1566. {
  1567.     register int x;
  1568.  
  1569.     x = strlen(src1);
  1570.     if (x == 0)
  1571.     return ap_pstrcat(a, "/", src2, NULL);
  1572.  
  1573.     if (src1[x - 1] != '/')
  1574.     return ap_pstrcat(a, src1, "/", src2, NULL);
  1575.     else
  1576.     return ap_pstrcat(a, src1, src2, NULL);
  1577. }
  1578.  
  1579. /*
  1580.  * Check for an absoluteURI syntax (see section 3.2 in RFC2068).
  1581.  */
  1582. API_EXPORT(int) ap_is_url(const char *u)
  1583. {
  1584.     register int x;
  1585.  
  1586.     for (x = 0; u[x] != ':'; x++) {
  1587.     if ((!u[x]) ||
  1588.         ((!ap_isalpha(u[x])) && (!ap_isdigit(u[x])) &&
  1589.          (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
  1590.         return 0;
  1591.     }
  1592.     }
  1593.  
  1594.     return (x ? 1 : 0);        /* If the first character is ':', it's broken, too */
  1595. }
  1596.  
  1597. API_EXPORT(int) ap_can_exec(const struct stat *finfo)
  1598. {
  1599. #ifdef MULTIPLE_GROUPS
  1600.     int cnt;
  1601. #endif
  1602. #if defined(OS2) || defined(WIN32)
  1603.     /* OS/2 dosen't have Users and Groups */
  1604.     return 1;
  1605. #else
  1606.     if (ap_user_id == finfo->st_uid)
  1607.     if (finfo->st_mode & S_IXUSR)
  1608.         return 1;
  1609.     if (ap_group_id == finfo->st_gid)
  1610.     if (finfo->st_mode & S_IXGRP)
  1611.         return 1;
  1612. #ifdef MULTIPLE_GROUPS
  1613.     for (cnt = 0; cnt < NGROUPS_MAX; cnt++) {
  1614.     if (group_id_list[cnt] == finfo->st_gid)
  1615.         if (finfo->st_mode & S_IXGRP)
  1616.         return 1;
  1617.     }
  1618. #endif
  1619.     return (finfo->st_mode & S_IXOTH);
  1620. #endif
  1621. }
  1622.  
  1623. #ifdef NEED_STRDUP
  1624. char *strdup(const char *str)
  1625. {
  1626.     char *sdup;
  1627.  
  1628.     if (!(sdup = (char *) malloc(strlen(str) + 1))) {
  1629.     fprintf(stderr, "Ouch!  Out of memory in our strdup()!\n");
  1630.     return NULL;
  1631.     }
  1632.     sdup = strcpy(sdup, str);
  1633.  
  1634.     return sdup;
  1635. }
  1636. #endif
  1637.  
  1638. /* The following two routines were donated for SVR4 by Andreas Vogel */
  1639. #ifdef NEED_STRCASECMP
  1640. int strcasecmp(const char *a, const char *b)
  1641. {
  1642.     const char *p = a;
  1643.     const char *q = b;
  1644.     for (p = a, q = b; *p && *q; p++, q++) {
  1645.     int diff = ap_tolower(*p) - ap_tolower(*q);
  1646.     if (diff)
  1647.         return diff;
  1648.     }
  1649.     if (*p)
  1650.     return 1;        /* p was longer than q */
  1651.     if (*q)
  1652.     return -1;        /* p was shorter than q */
  1653.     return 0;            /* Exact match */
  1654. }
  1655.  
  1656. #endif
  1657.  
  1658. #ifdef NEED_STRNCASECMP
  1659. int strncasecmp(const char *a, const char *b, int n)
  1660. {
  1661.     const char *p = a;
  1662.     const char *q = b;
  1663.  
  1664.     for (p = a, q = b; /*NOTHING */ ; p++, q++) {
  1665.     int diff;
  1666.     if (p == a + n)
  1667.         return 0;        /*   Match up to n characters */
  1668.     if (!(*p && *q))
  1669.         return *p - *q;
  1670.     diff = ap_tolower(*p) - ap_tolower(*q);
  1671.     if (diff)
  1672.         return diff;
  1673.     }
  1674.     /*NOTREACHED */
  1675. }
  1676. #endif
  1677.  
  1678. /* The following routine was donated for UTS21 by dwd@bell-labs.com */
  1679. #ifdef NEED_STRSTR
  1680. char *strstr(char *s1, char *s2)
  1681. {
  1682.     char *p1, *p2;
  1683.     if (*s2 == '\0') {
  1684.     /* an empty s2 */
  1685.         return(s1);
  1686.     }
  1687.     while((s1 = strchr(s1, *s2)) != NULL) {
  1688.     /* found first character of s2, see if the rest matches */
  1689.         p1 = s1;
  1690.         p2 = s2;
  1691.         while (*++p1 == *++p2) {
  1692.             if (*p1 == '\0') {
  1693.                 /* both strings ended together */
  1694.                 return(s1);
  1695.             }
  1696.         }
  1697.         if (*p2 == '\0') {
  1698.             /* second string ended, a match */
  1699.             break;
  1700.         }
  1701.     /* didn't find a match here, try starting at next character in s1 */
  1702.         s1++;
  1703.     }
  1704.     return(s1);
  1705. }
  1706. #endif
  1707.  
  1708. #ifdef NEED_INITGROUPS
  1709. int initgroups(const char *name, gid_t basegid)
  1710. {
  1711. #if defined(QNX) || defined(MPE) || defined(BEOS) || defined(_OSD_POSIX) || defined(TPF)
  1712. /* QNX, MPE and BeOS do not appear to support supplementary groups. */
  1713.     return 0;
  1714. #else /* ndef QNX */
  1715.     gid_t groups[NGROUPS_MAX];
  1716.     struct group *g;
  1717.     int index = 0;
  1718.  
  1719.     setgrent();
  1720.  
  1721.     groups[index++] = basegid;
  1722.  
  1723.     while (index < NGROUPS_MAX && ((g = getgrent()) != NULL))
  1724.     if (g->gr_gid != basegid) {
  1725.         char **names;
  1726.  
  1727.         for (names = g->gr_mem; *names != NULL; ++names)
  1728.         if (!strcmp(*names, name))
  1729.             groups[index++] = g->gr_gid;
  1730.     }
  1731.  
  1732.     endgrent();
  1733.  
  1734.     return setgroups(index, groups);
  1735. #endif /* def QNX */
  1736. }
  1737. #endif /* def NEED_INITGROUPS */
  1738.  
  1739. #ifdef NEED_WAITPID
  1740. /* From ikluft@amdahl.com
  1741.  * this is not ideal but it works for SVR3 variants
  1742.  * Modified by dwd@bell-labs.com to call wait3 instead of wait because
  1743.  *   apache started to use the WNOHANG option.
  1744.  */
  1745. int waitpid(pid_t pid, int *statusp, int options)
  1746. {
  1747.     int tmp_pid;
  1748.     if (kill(pid, 0) == -1) {
  1749.     errno = ECHILD;
  1750.     return -1;
  1751.     }
  1752.     while (((tmp_pid = wait3(statusp, options, 0)) != pid) &&
  1753.         (tmp_pid != -1) && (tmp_pid != 0) && (pid != -1))
  1754.     ;
  1755.     return tmp_pid;
  1756. }
  1757. #endif
  1758.  
  1759. API_EXPORT(int) ap_ind(const char *s, char c)
  1760. {
  1761.     register int x;
  1762.  
  1763.     for (x = 0; s[x]; x++)
  1764.     if (s[x] == c)
  1765.         return x;
  1766.  
  1767.     return -1;
  1768. }
  1769.  
  1770. API_EXPORT(int) ap_rind(const char *s, char c)
  1771. {
  1772.     register int x;
  1773.  
  1774.     for (x = strlen(s) - 1; x != -1; x--)
  1775.     if (s[x] == c)
  1776.         return x;
  1777.  
  1778.     return -1;
  1779. }
  1780.  
  1781. API_EXPORT(void) ap_str_tolower(char *str)
  1782. {
  1783.     while (*str) {
  1784.     *str = ap_tolower(*str);
  1785.     ++str;
  1786.     }
  1787. }
  1788.  
  1789. API_EXPORT(uid_t) ap_uname2id(const char *name)
  1790. {
  1791. #ifdef WIN32
  1792.     return (1);
  1793. #else
  1794.     struct passwd *ent;
  1795.  
  1796.     if (name[0] == '#')
  1797.     return (atoi(&name[1]));
  1798.  
  1799.     if (!(ent = getpwnam(name))) {
  1800.     fprintf(stderr, "%s: bad user name %s\n", ap_server_argv0, name);
  1801.     exit(1);
  1802.     }
  1803.     return (ent->pw_uid);
  1804. #endif
  1805. }
  1806.  
  1807. API_EXPORT(gid_t) ap_gname2id(const char *name)
  1808. {
  1809. #ifdef WIN32
  1810.     return (1);
  1811. #else
  1812.     struct group *ent;
  1813.  
  1814.     if (name[0] == '#')
  1815.     return (atoi(&name[1]));
  1816.  
  1817.     if (!(ent = getgrnam(name))) {
  1818.     fprintf(stderr, "%s: bad group name %s\n", ap_server_argv0, name);
  1819.     exit(1);
  1820.     }
  1821.     return (ent->gr_gid);
  1822. #endif
  1823. }
  1824.  
  1825.  
  1826. /*
  1827.  * Parses a host of the form <address>[:port]
  1828.  * :port is permitted if 'port' is not NULL
  1829.  */
  1830. unsigned long ap_get_virthost_addr(char *w, unsigned short *ports)
  1831. {
  1832.     struct hostent *hep;
  1833.     unsigned long my_addr;
  1834.     char *p;
  1835.  
  1836.     p = strchr(w, ':');
  1837.     if (ports != NULL) {
  1838.     *ports = 0;
  1839.     if (p != NULL && strcmp(p + 1, "*") != 0)
  1840.         *ports = atoi(p + 1);
  1841.     }
  1842.  
  1843.     if (p != NULL)
  1844.     *p = '\0';
  1845.     if (strcmp(w, "*") == 0) {
  1846.     if (p != NULL)
  1847.         *p = ':';
  1848.     return htonl(INADDR_ANY);
  1849.     }
  1850.  
  1851.     my_addr = ap_inet_addr((char *)w);
  1852.     if (my_addr != INADDR_NONE) {
  1853.     if (p != NULL)
  1854.         *p = ':';
  1855.     return my_addr;
  1856.     }
  1857.  
  1858.     hep = gethostbyname(w);
  1859.  
  1860.     if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) {
  1861.     fprintf(stderr, "Cannot resolve host name %s --- exiting!\n", w);
  1862.     exit(1);
  1863.     }
  1864.  
  1865.     if (hep->h_addr_list[1]) {
  1866.     fprintf(stderr, "Host %s has multiple addresses ---\n", w);
  1867.     fprintf(stderr, "you must choose one explicitly for use as\n");
  1868.     fprintf(stderr, "a virtual host.  Exiting!!!\n");
  1869.     exit(1);
  1870.     }
  1871.  
  1872.     if (p != NULL)
  1873.     *p = ':';
  1874.  
  1875.     return ((struct in_addr *) (hep->h_addr))->s_addr;
  1876. }
  1877.  
  1878.  
  1879. static char *find_fqdn(pool *a, struct hostent *p)
  1880. {
  1881.     int x;
  1882.  
  1883.     if (!strchr(p->h_name, '.')) {
  1884.     for (x = 0; p->h_aliases[x]; ++x) {
  1885.         if (strchr(p->h_aliases[x], '.') &&
  1886.         (!strncasecmp(p->h_aliases[x], p->h_name, strlen(p->h_name))))
  1887.         return ap_pstrdup(a, p->h_aliases[x]);
  1888.     }
  1889.     return NULL;
  1890.     }
  1891.     return ap_pstrdup(a, (void *) p->h_name);
  1892. }
  1893.  
  1894. char *ap_get_local_host(pool *a)
  1895. {
  1896. #ifndef MAXHOSTNAMELEN
  1897. #define MAXHOSTNAMELEN 256
  1898. #endif
  1899.     char str[MAXHOSTNAMELEN + 1];
  1900.     char *server_hostname;
  1901.     struct hostent *p;
  1902.  
  1903.     if (gethostname(str, sizeof(str) - 1) != 0) {
  1904.     perror("Unable to gethostname");
  1905.     exit(1);
  1906.     }
  1907.     str[MAXHOSTNAMELEN] = '\0';
  1908.     if ((!(p = gethostbyname(str))) || (!(server_hostname = find_fqdn(a, p)))) {
  1909.     fprintf(stderr, "%s: cannot determine local host name.\n",
  1910.         ap_server_argv0);
  1911.     fprintf(stderr, "Use the ServerName directive to set it manually.\n");
  1912.     exit(1);
  1913.     }
  1914.  
  1915.     return server_hostname;
  1916. }
  1917.  
  1918. /* aaaack but it's fast and const should make it shared text page. */
  1919. static const unsigned char pr2six[256] =
  1920. {
  1921.     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  1922.     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  1923.     64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, 52, 53, 54,
  1924.     55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3,
  1925.     4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
  1926.     22, 23, 24, 25, 64, 64, 64, 64, 64, 64, 26, 27, 28, 29, 30, 31, 32,
  1927.     33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
  1928.     50, 51, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  1929.     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  1930.     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  1931.     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  1932.     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  1933.     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  1934.     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  1935.     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
  1936. };
  1937.  
  1938. API_EXPORT(char *) ap_uudecode(pool *p, const char *bufcoded)
  1939. {
  1940.     int nbytesdecoded;
  1941.     register const unsigned char *bufin;
  1942.     register char *bufplain;
  1943.     register unsigned char *bufout;
  1944.     register int nprbytes;
  1945.  
  1946.     /* Strip leading whitespace. */
  1947.  
  1948.     while (*bufcoded == ' ' || *bufcoded == '\t')
  1949.     bufcoded++;
  1950.  
  1951.     /* Figure out how many characters are in the input buffer.
  1952.      * Allocate this many from the per-transaction pool for the result.
  1953.      */
  1954. #ifndef CHARSET_EBCDIC
  1955.     bufin = (const unsigned char *) bufcoded;
  1956.     while (pr2six[*(bufin++)] <= 63);
  1957.     nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
  1958.     nbytesdecoded = ((nprbytes + 3) / 4) * 3;
  1959.  
  1960.     bufplain = ap_palloc(p, nbytesdecoded + 1);
  1961.     bufout = (unsigned char *) bufplain;
  1962.  
  1963.     bufin = (const unsigned char *) bufcoded;
  1964.  
  1965.     while (nprbytes > 0) {
  1966.     *(bufout++) =
  1967.         (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
  1968.     *(bufout++) =
  1969.         (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
  1970.     *(bufout++) =
  1971.         (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
  1972.     bufin += 4;
  1973.     nprbytes -= 4;
  1974.     }
  1975.  
  1976.     if (nprbytes & 03) {
  1977.     if (pr2six[bufin[-2]] > 63)
  1978.         nbytesdecoded -= 2;
  1979.     else
  1980.         nbytesdecoded -= 1;
  1981.     }
  1982.     bufplain[nbytesdecoded] = '\0';
  1983. #else /*CHARSET_EBCDIC*/
  1984.     bufin = (const unsigned char *) bufcoded;
  1985.     while (pr2six[os_toascii[(unsigned char)*(bufin++)]] <= 63);
  1986.     nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
  1987.     nbytesdecoded = ((nprbytes + 3) / 4) * 3;
  1988.  
  1989.     bufplain = ap_palloc(p, nbytesdecoded + 1);
  1990.     bufout = (unsigned char *) bufplain;
  1991.  
  1992.     bufin = (const unsigned char *) bufcoded;
  1993.  
  1994.     while (nprbytes > 0) {
  1995.     *(bufout++) = os_toebcdic[
  1996.         (unsigned char) (pr2six[os_toascii[*bufin]] << 2 | pr2six[os_toascii[bufin[1]]] >> 4)];
  1997.     *(bufout++) = os_toebcdic[
  1998.         (unsigned char) (pr2six[os_toascii[bufin[1]]] << 4 | pr2six[os_toascii[bufin[2]]] >> 2)];
  1999.     *(bufout++) = os_toebcdic[
  2000.         (unsigned char) (pr2six[os_toascii[bufin[2]]] << 6 | pr2six[os_toascii[bufin[3]]])];
  2001.     bufin += 4;
  2002.     nprbytes -= 4;
  2003.     }
  2004.  
  2005.     if (nprbytes & 03) {
  2006.     if (pr2six[os_toascii[bufin[-2]]] > 63)
  2007.         nbytesdecoded -= 2;
  2008.     else
  2009.         nbytesdecoded -= 1;
  2010.     }
  2011.     bufplain[nbytesdecoded] = '\0';
  2012. #endif /*CHARSET_EBCDIC*/
  2013.     return bufplain;
  2014. }
  2015.  
  2016. static const char basis_64[] = 
  2017. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 
  2018.  
  2019. API_EXPORT(char *) ap_uuencode(pool *a, char *string) 
  2020.     int i, len = strlen(string); 
  2021.     char *p; 
  2022.     char *encoded = (char *) ap_palloc(a, (len+2) / 3 * 4); 
  2023.  
  2024.     p = encoded; 
  2025. #ifndef CHARSET_EBCDIC
  2026.     for (i = 0; i < len-2; i += 3) { 
  2027.         *p++ = basis_64[(string[i] >> 2) & 0x3F]; 
  2028.         *p++ = basis_64[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)]; 
  2029.         *p++ = basis_64[((string[i + 1] & 0xF) << 2) | ((int) (string[i + 2] & 0xC0) >> 6)]; 
  2030.         *p++ = basis_64[string[i + 2] & 0x3F]; 
  2031.     } 
  2032.     if (i < len) {
  2033.         *p++ = basis_64[(string[i] >> 2) & 0x3F]; 
  2034.        *p++ = basis_64[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)]; 
  2035.        if (i == (len-2))
  2036.            *p++ = basis_64[((string[i + 1] & 0xF) << 2)]; 
  2037.        else
  2038.            *p++ = '='; 
  2039.        *p++ = '='; 
  2040.     }
  2041. #else /*CHARSET_EBCDIC*/
  2042.     for (i = 0; i < len-2; i += 3) { 
  2043.         *p++ = basis_64[(os_toascii[string[i]] >> 2) & 0x3F]; 
  2044.         *p++ = basis_64[((os_toascii[string[i]] & 0x3) << 4) | ((int) (os_toascii[string[i + 1]] & 0xF0) >> 4)]; 
  2045.         *p++ = basis_64[((os_toascii[string[i + 1]] & 0xF) << 2) | ((int) (os_toascii[string[i + 2]] & 0xC0) >> 6)]; 
  2046.         *p++ = basis_64[os_toascii[string[i + 2]] & 0x3F]; 
  2047.     } 
  2048.     if (i < len) {
  2049.         *p++ = basis_64[(os_toascii[string[i]] >> 2) & 0x3F]; 
  2050.        *p++ = basis_64[((os_toascii[string[i]] & 0x3) << 4) | ((int) (os_toascii[string[i + 1]] & 0xF0) >> 4)]; 
  2051.        if (i == (len-2))
  2052.            *p++ = basis_64[((os_toascii[string[i + 1]] & 0xF) << 2)]; 
  2053.        else
  2054.            *p++ = '='; 
  2055.        *p++ = '='; 
  2056.     }
  2057. #endif /*CHARSET_EBCDIC*/
  2058.  
  2059.     *p = '\0'; 
  2060.     return encoded; 
  2061.  
  2062. #ifdef OS2
  2063. void os2pathname(char *path)
  2064. {
  2065.     char newpath[MAX_STRING_LEN];
  2066.     int loop;
  2067.     int offset;
  2068.  
  2069.     offset = 0;
  2070.     for (loop = 0; loop < (strlen(path) + 1) && loop < sizeof(newpath) - 1; loop++) {
  2071.     if (path[loop] == '/') {
  2072.         newpath[offset] = '\\';
  2073.         /*
  2074.            offset = offset + 1;
  2075.            newpath[offset] = '\\';
  2076.          */
  2077.     }
  2078.     else
  2079.         newpath[offset] = path[loop];
  2080.     offset = offset + 1;
  2081.     };
  2082.     /* Debugging code */
  2083.     /* fprintf(stderr, "%s \n", newpath); */
  2084.  
  2085.     strcpy(path, newpath);
  2086. };
  2087. #endif
  2088.  
  2089.  
  2090. #ifdef NEED_STRERROR
  2091. char *
  2092.      strerror(int err)
  2093. {
  2094.  
  2095.     char *p;
  2096.     extern char *const sys_errlist[];
  2097.  
  2098.     p = sys_errlist[err];
  2099.     return (p);
  2100. }
  2101. #endif
  2102.  
  2103. #if defined(NEED_DIFFTIME)
  2104. double difftime(time_t time1, time_t time0)
  2105. {
  2106.     return (time1 - time0);
  2107. }
  2108. #endif
  2109.  
  2110. /* we want to downcase the type/subtype for comparison purposes
  2111.  * but nothing else because ;parameter=foo values are case sensitive.
  2112.  * XXX: in truth we want to downcase parameter names... but really,
  2113.  * apache has never handled parameters and such correctly.  You
  2114.  * also need to compress spaces and such to be able to compare
  2115.  * properly. -djg
  2116.  */
  2117. API_EXPORT(void) ap_content_type_tolower(char *str)
  2118. {
  2119.     char *semi;
  2120.  
  2121.     semi = strchr(str, ';');
  2122.     if (semi) {
  2123.     *semi = '\0';
  2124.     }
  2125.     while (*str) {
  2126.     *str = ap_tolower(*str);
  2127.     ++str;
  2128.     }
  2129.     if (semi) {
  2130.     *semi = ';';
  2131.     }
  2132. }
  2133.  
  2134. /*
  2135.  * Given a string, replace any bare " with \" .
  2136.  */
  2137. API_EXPORT(char *) ap_escape_quotes (pool *p, const char *instring)
  2138. {
  2139.     int newlen = 0;
  2140.     const char *inchr = instring;
  2141.     char *outchr, *outstring;
  2142.  
  2143.     /*
  2144.      * Look through the input string, jogging the length of the output
  2145.      * string up by an extra byte each time we find an unescaped ".
  2146.      */
  2147.     while (*inchr != '\0') {
  2148.     newlen++;
  2149.         if (*inchr == '"') {
  2150.         newlen++;
  2151.     }
  2152.     /*
  2153.      * If we find a slosh, and it's not the last byte in the string,
  2154.      * it's escaping something - advance past both bytes.
  2155.      */
  2156.     if ((*inchr == '\\') && (inchr[1] != '\0')) {
  2157.         inchr++;
  2158.         newlen++;
  2159.     }
  2160.     inchr++;
  2161.     }
  2162.     outstring = ap_palloc(p, newlen + 1);
  2163.     inchr = instring;
  2164.     outchr = outstring;
  2165.     /*
  2166.      * Now copy the input string to the output string, inserting a slosh
  2167.      * in front of every " that doesn't already have one.
  2168.      */
  2169.     while (*inchr != '\0') {
  2170.     if ((*inchr == '\\') && (inchr[1] != '\0')) {
  2171.         *outchr++ = *inchr++;
  2172.         *outchr++ = *inchr++;
  2173.     }
  2174.     if (*inchr == '"') {
  2175.         *outchr++ = '\\';
  2176.     }
  2177.     if (*inchr != '\0') {
  2178.         *outchr++ = *inchr++;
  2179.     }
  2180.     }
  2181.     *outchr = '\0';
  2182.     return outstring;
  2183. }
  2184.